#ifndef __POLYTASK_H__
#define __POLYTASK_H__

#include "cnc/cnc.h"
#include "cnc/default_tuner.h"

using namespace std;

#include "cnc/debug.h"

// forward declaration
template <int TASK_ID, int TASKTAGDIM, int INTERINTERTASKDIM>
class polyTask_context;

#include "TaskTag.hpp"

// PolyTask core class
template <int TASK_ID, int TASKTAGDIM, int INTERINTERTASKDIM> class polyTask_step {
public:
  int64_t execute
  (const TaskTag<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> &, 
   polyTask_context<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> &) const;
};

// PolyTask tuner class
template <int TASK_ID, int TASKTAGDIM, int INTERINTERTASKDIM> class polyTask_tuner : 
  public CnC::step_tuner<>, public CnC::tag_tuner<>, public CnC::hashmap_tuner {
public:
  polyTask_tuner() {}
  template< class DC >
  void depends(const TaskTag<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> &, 
               polyTask_context<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> &, DC &) const;
};


// Context for a single polyTask 
template <int TASK_ID, int TASKTAGDIM, int INTERINTERTASKDIM> class polyTask_context : 
public CnC::context< polyTask_context<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> > {
public:
  polyTask_tuner <TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> m_tuner;

  CnC::item_collection< TaskTag<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM>, 
                        void *, polyTask_tuner<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> > M;

  CnC::step_collection< polyTask_step<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM>, 
                        polyTask_tuner<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> 
                        > m_steps;

  CnC::tag_collection< TaskTag<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> , 
                       polyTask_tuner<TASK_ID, TASKTAGDIM, INTERINTERTASKDIM> 
                       > m_tags;

  polyTask_context() : 
    m_tuner(), 
    M(*this, "M", m_tuner), 
    m_tags(*this), m_steps(*this) {

    // prescription
    m_tags.prescribes( m_steps, *this );

    // producer/consumer
    m_steps.consumes( M );
    m_steps.produces( M );
  }

};


#endif
